OLE, pronounced Olé! (like at a fiesta), and an acronym for "Object Linking and Embedding," is a standard that provides several ways for software programs to communicate with each other. Visual Basic 4.0 has fully implemented OLE 2.x and
this has expanded the collection of tools available in the product. A working understanding of objects and OLE 2.x is required in order to get the greatest value from the changes in VB 4.0.
Microsoft's position is that OLE 2.x is not just object linking and embedding anymore. The second (and current version) of the standard has expanded the focus of OLE to include a standard for interapplication communication. One good way to summarize the
differences between OLE 1.0 and OLE 2.x, is that 1.0 was about object linking and embedding, whereas OLE 2.0 is about objects, and linking and embedding are only one part of the picture.
This chapter begins with a discussion of the object linking and embedding technology. If you already have a basic understanding of OLE 2.x technology, then you might skip or skim the first section as a review. The following section discusses Visual
Basic's place in the world of OLE 2.x. The third section explores Visual Basic 4.0's place as an object oriented programming language. It discusses ways to implement object oriented design techniques providing VB programmers with reusable code and
bulletproof applications. The final section presents some resources for further information on object linking and embedding.
"Object" is one of the most abstract and amorphous words in the English language. Just about any entity we can talk about qualifies as an object. Webster's Dictionary defines an object in this way:
(1) |
ob.ject)(n)(14c)<objectum, >fr. L, neut. of ><obicere >to throw in the way, present, hinder, fr. ><ob-> in the way + ><jacere >to throw |
1a: |
something material that may be perceived by the senses <I see an object in the distance.> |
1b: |
something that when viewed stirs a particular emotion (as pity) <look to the tragic loading of this bed ... the object poisons sight; let it be hid —Shak.> |
2: |
something mental or physical toward which thought, feeling, or action is directed <an object for study> <the object of my affection> <delicately carved art objects> |
3: |
the goal or end of an effort or activity: PURPOSE, OBJECTIVE <their object is to investigate the matter thoroughly> |
4: |
a thing that forms an element of or constitutes the subject matter of an investigation or science |
5a: |
a noun or noun equivalent (as a pronoun, gerund, or clause) denoting the goal or result of the action of a verb |
5b: |
a noun or noun equivalent in a prepositional phrase |
The software industry has developed several meanings of the term, "object." Marketing types have appropriated the word and turned "object-oriented" into a buzzword. Almost every major piece of software claims to be object oriented.
To restore some clarity, here are some of the relevant definitions of objects:
Object-oriented software theorists understand an object to be a component of a software program that "models" or "represents" a something in the real world, like a ledger or a bicycle. Because of this correlation between real world
and software objects, it is allegedly easier to construct re-usable software components and to reduce bugs by isolating one module of a program from changes in another. In order to qualify as an object, the design must support four qualities:
Devout OOP programmers vehemently argue whether OLE 2.x "objects" deserve the name. It's something of an irony that theorists would choose one of the most vague words in the English language and then get huffy about the imprecise use of the
term. We'll explore the details of this is the third section of this chapter.
From Visual Basic's perspective, objects are combinations of code and data that function as a unit. In another sense, an object is a user interface element in Windows (or any other operating system), for example, a program window, a text box, a command
button, and so on.
Finally in the pure sense of object linking and embedding, an object is a self-contained bit of information that lives in a compound document. It behaves the same regardless of the application that manages the compound document because the object
determines its own behavior. Such an object has two levels of data: presentation data and native data. Presentation data allows the object to be viewed on screen or in print. Native data is the binary information stored in random access memory or on disk
and underlies the presentation. In linking, the native data resides on the user's disk in a separate file or document; in embedding, the native data resides in the compound document itself.
It is helpful to review the history of object linking and embedding, which may help clarify the muddle. This "history" might be subtitled "The Quest for Integration," because it is driven by the need to provide the end-user with
tools to assemble data in different formats into cohesive presentations or documents. To make this more vivid, let's take the example of Joe User who has the following task to perform: He needs to analyze sales performance for four divisions of the
company, and send this analysis along with a cover letter to all sales personnel in the company.
Back before the birth of graphical user interfaces, we were stuck with applications that couldn't communicate with each other.
Joe uses a flat file database, a character mode spreadsheet and a character mode word processor. To accomplish this task he opens the database program and exports a tab delimited text file containing the list of sales personnel and their addresses. Then
he closes the database. He opens a spreadsheet program and creates a spreadsheet in which he constructs a summary table of sales information based on other spreadsheets. This, in itself, could get pretty tedious because the spreadsheet may not support
multiple open files. He prints copies of the spreadsheet, closes the spreadsheet program, and then he opens the word processor. He types a mail merge letter laboriously, and retypes the spreadsheet information into the word processor as a table (with tab
characters separating the report columns). He prints the letter several times to get the formatting and alignment just right, then he runs the mail merge. Finally, he stuffs envelopes, feeds them through a postage meter, and sends them on their way. Yes,
it's easier than doing it with a ledger and a typewriter, but....
Along comes Windows, or Desqview, or a Macintosh, and Joe's work gets a little easier; he can switch between running applications and he can use a clipboard. He still needs to save the database information in a format his word processor can understand,
but he can copy parts of the spreadsheet directly into his document. However, it needs to be reformatted to look good, and if the data in the spreadsheet changes, he has to repeat this process. It is very easy for errors to slip into the process and bosses
being the way they are, well....
Windows 2.1 comes with Dynamic Data Exchange (DDE) and links. Joe's word processor might even be able to read the database tables directly for the mail merge, and using Excel or some other Windows-based spreadsheet he can paste a link into his Word
document that always reflects the current state of the spreadsheet data in the document. Unfortunately, DDE is slow. When Joe uses this approach, Windows often crashes mysteriously (remember UAEs, Unforgivable Application Errors), and he can only transfer
text, not graphs or pictures.
Windows 3.x and OLE 1.0 comes along. Now Joe can either embed or link the spreadsheet data into his document. If he double-clicks on the embedded or linked data, the spreadsheet application launches in a separate window and Joe can edit the data
directly. He can use graphs from the spreadsheet, and the data is always up to date, but the system slows to a crawl with multiple applications running, and it seems to take forever when switching between editing applications.
OLE 2.x comes along. Now when Joe double-clicks on his spreadsheet data, the toolbars and menus of the word processor change to those from the spreadsheet. When he clicks outside of the spreadsheet object, they return to the usual ones for the
application. If he has both applications running, he can actually drag a selection from one application into another with his mouse. Although it feels like developing a single document in a single application, he now has the ability to develop compound
documents that hold OLE 2.x objects from a variety of sources. Applications that support compound documents can allow him to edit the various components transparently. Additionally, instead of paper mail, he can broadcast these letters across the network
as attachments to e-mail messages that can be dispatched directly from the word processor. The applications he uses are large and require a lot of memory, and he has to add more RAM to his machine. Even after adding a substantial amount of RAM, he gets
these mysterious out-of-memory messages from Windows when he is really only out of resources. Finally, some of these maneuvers can still be pretty slow on the hardware bought just a year or two ago. Joe is now working on a network and unfortunately some of
these nifty features do not work across the network.
Microsoft is promising a standard for distributed OLE so that Joe will be able to use objects across the network from applications that are actually running on other computers. This is yet to be seen.
Through OLE 2.x, computer programs are assisting users to move from a program-centric model of computing to a document-, or data-centric model. In the program-centric model, considerable learning is required to master the foibles of different programs
and there are difficulties involved in presenting information in various formats (graphs, pictures, tabular data, formatted text) in the same document or presentation. In the document-centric model (which is yet to be fully realized) a user can
transparently assemble information in different formats and present it to others while focusing only on meaning and content. This is a work in progress and the transition is far from complete.
OLE 2.x is a complex technology that has been notoriously difficult for developers to implement. It is constructed on a layered model as shown in Figure 16.1. The upper layer describes the features available for use by (or customization for) the end
user. The infrastructure describes the low level services that are managed by the operating system and by Visual Basic. For the most part, the Visual Basic programmer is shielded from these details. The grayed areas of the model are areas of special
interest for Visual Basic programmers. Interface in OLE is a means by which two programs communicate with each other: for example, drag and drop, or programmability.
Figure 16.1. The Layered model of OLE 2.x.
OLE 2.x is based on the Component Object Model or COM. You might say that COM acts like a dating service for software components, introducing them and then slipping into the background while they communicate. It continues to work in the background
managing the infrastructure services.
From the user's point of view, OLE 2.x provides the following features:
Visual editing or in-place activation is how embedded or linked objects present themselves in an OLE 2.x-aware application. Instead of opening a separate window for editing, the menus and toolbars of the client application change and display the menus
and toolbars of the server application.
OLE 2.x compound documents allow for nested objects, so one could place a graphic object on a spreadsheet table inside a word processing document.
Drag and drop allows the use of the mouse to transfer data from one application to another without using the Clipboard. There are three levels of drag and drop functionality in OLE 2.x:
Finally, and probably most importantly to VB programmers, OLE 2.x Automation allows objects to expose a programmable interface to OLE 2.x-aware programming and macro languages. This allows programmers to develop integrated solutions that utilize
features of several applications to automate tasks for end-users.
In summary, in the wonderful world of OLE 2.x there are really two types of objects: programmable objects and non-programmable objects. Non-programmable objects are components of compound documents. They reside in the interface between users and
documents. Examples of this type of object are sounds, animations, text, spreadsheet tables, and graphics, in other words, "multimedia." Programmable objects, or OLE 2.x Automation objects, reside in the interface between programmers and
production software. They allow themselves to be manipulated through properties and methods.
Visual Basic interacts with both programmable and non-programmable OLE 2.x objects. Table 16.1 describes the implementation of OLE services in Visual Basic 4.0. It includes only those services that are native to Visual Basic 4.0. Other support may be
available in add-ins and third party custom controls.
OLE 2.x service |
Visual Basic Support |
Visual Editing |
Visual Basic forms in conjunction with the OLE container control support visual editing with toolbar and menu negotiation, that is, they allow the menus and toolbars of a Visual Basic application to update with information from server applications. |
Compound documents |
You can display compound documents in a Visual Basic form or in an OLE 2.x container control, previously called the OLE custom control in Visual Basic 3.0; however, you may not create a server application that provides OLE 2.x non-programmable objects similar to Visio drawings or Word documents. |
Non-programmable objects |
These can be embedded or linked to Visual Basic forms and OLE container controls. |
Drag and Drop |
The OLE container control can function as the target for an interapplication drag and drop maneuver. |
OLE Automation |
Fully supported as both a controller and as an object itself. |
Right off the bat, it's important to point out what Visual Basic cannot do: it cannot create an application that manages compound documents and provides objects to fill them. You cannot write a Visio, Microsoft WordArt, or the answer to Excel in Visual
Basic, but there is interesting new support for non-programmable OLE objects in Visual Basic.
Visual Basic forms can function as OLE containers without using the OLE 2.x control. One can place objects like graphs, drawings, and sounds directly on forms. The objects will even show up in the Toolbox window, and you can draw them directly on the
form in the same way that you draw controls (see Figure 16.2).
Figure 16.2. Tools for Excel and Word are displayed in the Visual Basic 4.0 Toolbox window.
In this way, a programmer can produce an interface that uses elements from various applications for an integrated presentation on-screen, for example, in EIS (Executive Information Systems) applications (see Figure 16.3). There are several examples of
this type of program in the Microsoft Office Developers Kit which is included with the Professional Edition of Visual Basic 4.0.
Figure 16.3. An EIS application from the Office Developers Kit.
Although this application, developed in Visual Basic 3.0, uses OLE custom controls to contain the various elements, Visual Basic 4.0 supports drawing them directly on forms.
Even though there is direct support for insertable objects on Visual Basic forms, there are additional advantages to be gained by using the OLE control.
This application consists of a single form with six controls. The controls are:
Figure 16.4 shows the Viewer project in the development environment.
Figure 16.4. The OLE Viewer form in the development environment.
There is one menu with two submenus. Figure 16.5 shows the Menu Design window with the menus for the OLE Viewer.
Figure 16.5. The Menu Design window.
Figure 16.6. The OLE Viewer application running.
Following is the code for the entire application. Figure 16.6 shows the application running.
VERSION 4.00 Begin VB.Form Form1 Caption = "Form1" ClientHeight = 4935 ClientLeft = 1410 ClientTop = 1815 ClientWidth = 6060 Height = 5625 Left = 1350 LinkTopic = "Form1" ScaleHeight = 4935 ScaleWidth = 6060 Top = 1185 WhatsThisButton = -1 'True WhatsThisHelp = -1 'True Width = 6180 Begin VB.ListBox List1 Height = 840 Index = 2 Left = 4020 TabIndex = 4 Top = 660 Width = 1815 End Begin VB.ListBox List1 Height = 840 Index = 1 Left = 2100 TabIndex = 3 Top = 660 Width = 1815 End Begin VB.ListBox List1 Height = 840 Index = 0 Left = 180 TabIndex = 2 Top = 660 Width = 1815 End Begin VB.Label Label1 AutoSize = -1 'True Caption = "Object Get Formats" Height = 195 Index = 2 Left = 4020 TabIndex = 8 Top = 420 Width = 1365 End Begin VB.Label Label1 AutoSize = -1 'True Caption = "Object Accept Formats" Height = 195 Index = 1 Left = 2100 TabIndex = 7 Top = 420 Width = 1620 End Begin VB.Label Label1 Caption = "Object Verbs" Height = 195 Index = 0 Left = 180 TabIndex = 6 Top = 420 Width = 1035 End Begin ComctlLib.StatusBar StatusBar1 Align = 2 'Align Bottom Height = 255 Left = 0 Negotiate = -1 'True TabIndex = 5 Top = 4680 Width = 6060 _Version = 65536 _ExtentX = 10689 _ExtentY = 450 _StockProps = 68 AlignSet = -1 'True SimpleText = "" _timers = 2 NumPanels = 3 i1 = "Form1.frx":0000 i2 = "Form1.frx":010C i3 = "Form1.frx":01FB End Begin ComctlLib.Toolbar Toolbar1 Align = 1 'Align Top Height = 390 Left = 0 Negotiate = -1 'True TabIndex = 1 Top = 0 Width = 6060 _Version = 65536 _ExtentX = 10689 _ExtentY = 688 _StockProps = 100 ImageList = "" NumButtons = 2 i1 = "Form1.frx":02EA i2 = "Form1.frx":046A AlignSet = -1 'True End Begin VB.OLE OLE1 Height = 2895 Left = 180 TabIndex = 0 Top = 1620 Width = 5655 End Begin VB.Menu mnuFile Caption = "&File" NegotiatePosition= 1 'Left Begin VB.Menu mnuFileNewObject Caption = "&New Object" End Begin VB.Menu mnuFileSep1 Caption = "-" End Begin VB.Menu mnuFileExit Caption = "E&xit" End End End Attribute VB_Name = "Form1" Attribute VB_Creatable = False Attribute VB_Exposed = False Option Explicit Private Sub mnuFileExit_Click() Unload Me End Sub Private Sub mnuFileNewObject_Click() Dim I ' Declare counter variable. Dim Buffer As String 'for string manipulation 'Clear the OLE Control if it contains an object If OLE1.Class <> "" Then OLE1.Close End If ' Display the Insert Object dialog box. On Error GoTo ThisWayOut OLE1.InsertObjDlg On Error GoTo 0 ' Update the list of available verbs. Buffer = OLE1.Class Me.Caption = "This is not " & _ Left$(Buffer, InStr(Buffer, ".") - 1) & _ " running." OLE1.FetchVerbs ' Fetch verbs. ' Clear the list boxes. For I = 0 To 2 List1(I).Clear Next ' Fill the verbs list box. Because ObjectVerbs(0) is ' the default verb and is repeated in the ObjectVerbs() ' array, start the count at 1. For I = 1 To OLE1.ObjectVerbsCount - 1 List1(0).AddItem OLE1.ObjectVerbs(I) Next I 'Fill the Accept Formats list box. For I = 0 To OLE1.ObjectAcceptFormatsCount - 1 List1(1).AddItem OLE1.ObjectAcceptFormats(I) Next I ' Fill the Get Formats list box. For I = 0 To OLE1.ObjectGetFormatsCount - 1 List1(2).AddItem OLE1.ObjectGetFormats(I) Next I Exit Sub ThisWayOut: OLE1.Class = "" End Sub
I know that this borders on gushing, but OLE Automation is a magic kingdom for Visual Basic programmers. The syntax of OLE Automation is already well understood by anyone with even a passing understanding of Visual Basic. The level of integration and
customization of off-the-shelf and original Visual Basic software should provide Visual Basic users with fine economic opportunities for a long time to come.
In order to appreciate the wide range of new tools in Visual Basic 4.0, this section starts with a brief discussion of some of the underlying technology of OLE Automation, and a third-party tool that is very useful for exploring the capabilities of OLE
Automation servers. Then the section steps through the relevant features in Visual Basic 4.0. These include:
You use a rudimentary Visual Basic application, improving it at the various stages to illustrate the uses more concretely.
When an OLE Automation server is installed on a system, it must be registered in the system registry with information about the location of the server application or DLL and information about the objects it provides. When it is installed, the
application generates a file with a distinctive extension (*.tlb, *.olb, and *.ola are usual extensions). This file contains information about the programmable object the application exposes, including constants, properties, events (in the case of OLE
controls), and methods. These are defined in object definition language and compiled in a binary form that is not humanly readable.
In order to use the programmable objects, a programmer needs either documentation from the publisher of the software or a utility that displays the contents of the type library in an understandable format. Visual Basic for Applications and Visual Basic
4.0 contain a built-in Object Browser dialog that does this in a rudimentary way (see Figure 16.7). The first version of the Microsoft Developers Kit contained a free-standing version of the dialog as well.
Figure 16.7. The Object Browser in Visual Basic 4.0.
There are problems with the native Object Browser dialog, though. It lists all the properties, methods, and events for a particular object in a single list box in alphabetical order without any instruction about which item is a property or method or
whatever. You have the option of pasting from the dialog to your development environment but only as a declaration, for example "Const xlBar = 2". Although this is helpful as far as it goes, there is now a better alternative.
Apex Software has released a product called VBA Companion. This is the better mousetrap: a full-feature object browser. In addition to the services of the native object browser, VBA Companion separates properties, methods, and events into separate lists
but also provides immediate access to the full range of details (see Figure 16.8). Whereas the native browser only allows you to add comments to your own objects, VBA Companion allows you to add notes or annotations to the type libraries on your system to
help you with future use of the objects.
In addition to the clearer exposition of the contents of type libraries, VBA Companion allows you to paste information into your programs as comments, declarations, or statement/function templates. For example, VBA Companion copies this to the clipboard
when you use the context menu:
xlBar
But when you select it and use the Edit menu's Copy command, it copies the declaration
Const xlBar = 2
Similarly, for a function or sub, when you use the context menu it copies the template for a function or statement (this example uses a method of the Arc object in Excel 5.0).
arc.CopyPicture(Appearance:=, Format:=)
When you use the edit menu it copies the declaration and adds the End Function line, a feature that Visual Basic supplies automatically but Visual Basic for Applications does not.
Function CopyPicture (Appearance As Variant, Format As Variant) As Variant End Function
These features can be very helpful when one is struggling with object hierarchies from other applications.
To illustrate the range of OLE Automation services in Visual Basic, I have chosen the Run dialog. Frequently found in shell replacements and utilities for Windows, the Run dialog allows a user to enter a command line to be executed by Windows. Figure
16.9 shows the Run dialog from Windows 95.
Figure 16.9. The Run dialog from Windows 95.
You'll step this simple dialog through the various layers of OLE Automation support in Visual Basic 4.0. The form that functions as the run dialog has an image control with an icon in it, a text box, three command buttons, and a common dialog control.
Figure 16.10 shows the form for our Run dialog in the Visual Basic development environment.
Figure 16.10. The form for our Run dialog.
In Visual Basic 4.0, forms are fully qualified OLE objects. This means that, in addition to the event procedures and built-in properties, one can declare public variables and public functions that then function as custom methods and properties for the
form. In our example there is one private and one public variable declared at the Form level.
Option Explicit Public CommandLine As String Private boolOK As Boolean
There are two public functions declared at the form level; the first displays the dialog and the second executes the command line that the user has chosen in the dialog.
Public Function Display() As Boolean Me.Show vbModal Display = boolOK End Function Public Function Execute() As Variant Dim lngResult As Long 'This will return a variant of type error 'if the command line does not execute successfully 'Otherwise it returns the task ID as a variant 'to the calling procedure. On Error Resume Next lngResult = Shell(CommandLine, vbNormalFocus) If Err.Number <> 0 Then Execute = CVErr(Err.Number) Else Execute = lngResult End If End Function
The project contains a scaffold form with one command button on it to test the execution of the Run dialog. A scaffold form or program is software whose only reason for existing is to test modules in isolation from each other. The code in the scaffold
form demonstrates the syntax to use in addressing forms as objects.
Private Sub cmdRun_Click() Dim dlg As New dlgRun Dim success As Variant success = dlg.Display() MsgBox success If success Then MsgBox dlg.CommandLine success = dlg.Execute MsgBox success End If End Sub
A major side-effect of this implementation is that forms now support most of the module features in previous versions of Visual Basic. For example, variables declared as public are visible from other modules and forms by using the object.property
syntax. Forms now support public or private Declare and Const statements. One can now design sophisticated Visual Basic applications that only contain forms.
The Run dialog form can be added to any project and bring full functionality with it. With a simple dialog this would probably be adequate, but Visual Basic 4.0 goes further. In addition to greater functionality in forms, it adds the possibility for
developing a new kind of module, called a class module, which is, simply put, a fully functional OLE Automation object. You'll change your form into a fully functional OLE Automation server by adding a class module (*.CLS) to the project.
Instead of accessing the methods of the dlgRun form directly, you'll make the form a private element in the RunClass and only access it through methods of the RunClass.
The following is the text of the class module, RunClass.cls:
Option Explicit Private dlg As New dlgRun Public Property Get CommandLine() As Variant CommandLine = dlg.CommandLine End Property Public Function Execute() As Variant Dim varHolder As Variant varHolder = dlg.Execute If VarType(varHolder) = vbError Then Execute = False Else Execute = varHolder End If End Function Public Function Run() As Variant Run = dlg.Display If Run Then dlg.UpdateCommandLines End Function Private Sub Class_Initialize() Load dlg End Sub Private Sub Class_Terminate() Unload dlg Set dlg = Nothing End Sub
Some notes about the class module: The distinction between Private and Public properties and methods is supremely important. The underlying implementation in private methods and properties (in this case they are mostly contained in the Run dialog form)
can be changed as needed, but the interface that is exposed needs to remain consistent. The advantage of a consistent interface is that the program can be changed over time and still work with OLE controllers (also called client applications) without
breaking them or itself. It also demonstrates Property and Class procedures (new procedure types in Visual Basic 4.0). The Property procedures are transparent to the calling application as properties. They are addressed with simple assignment calls. Table
16.02 lists the syntax and effect of each type of Property procedure.
Syntax |
Effect |
MyProperty = NewValue |
Triggers the Property Let procedure |
Set MyObject = NewObject |
Triggers the Property Set procedure |
ThisValue = Object.Property |
Triggers the Property Get procedure |
This type of procedure allows special processing in response to assignment statements. In this example, all that happens is that information from the private form is expressed to other elements of the program. In more complex programs, this ability
could be very useful.
The second new type of procedures are Class procedures: Initialize() and Terminate(). These permit special processing when the object is created and destroyed. In object-oriented programming terminology, these would be called the constructor and
destructor for an object. In my experience, the Terminate procedure is most important because it allows necessary cleanup, especially when you are using objects inside the object. This cleanup ensures that any memory assignments are freed up when the
object exits.
To test this version, you are still using a scaffold application; there are some minor modifications in this version.
VERSION 4.00 Begin VB.Form frmScaffold Caption = "Form1" ClientHeight = 4140 ClientLeft = 1140 ClientTop = 1515 ClientWidth = 6690 Height = 4545 Left = 1080 LinkTopic = "Form1" ScaleHeight = 4140 ScaleWidth = 6690 Top = 1170 Width = 6810 Begin VB.CommandButton cmdUnload Caption = "Command1" Height = 795 Left = 420 TabIndex = 1 Top = 1680 Width = 2055 End Begin VB.CommandButton cmdRun Caption = "&Run" Height = 735 Left = 480 TabIndex = 0 Top = 660 Width = 1875 End End Attribute VB_Name = "frmScaffold" Attribute VB_Creatable = False Attribute VB_Exposed = False Option Explicit Dim obj As New RunClass Private Sub cmdRun_Click() Dim success As Variant success = obj.Run MsgBox obj.CommandLine success = obj.Execute End Sub Private Sub cmdUnload_Click() Unload Me End Sub Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer) Set obj = Nothing End Sub
Now, simply by replacing the scaffold form with a module and writing a Sub Main procedure, you have an OLE automation server that can be distributed either as an executable or, and this is quite an advance, as a dynamic link library. The ability to
create dynamic link libraries in Visual Basic is limited to OLE automation servers. Nonetheless, now Visual Basic programmers can distribute to other programmers components that are written entirely in Visual Basic without exposing code and providing
performance superior to compiled executables in Visual Basic.
This is the Sub main procedure for our object server.
Attribute VB_Name = "MainModule" Option Explicit Sub Main() 'Check to see if the application has 'been launched by a curious user If App.StartMode = vbSModeStandalone Then Dim msg As String, style As Integer msg = "This application cannot be run " _ & "as a stand alone executable. Sorry! " _ & "Exiting now." style = vbOK + vbExclamation MsgBox msg, style, "rbRun.exe" 'End '(the end statement is not supported in DLLs End If End Sub
The message is presented as a courtesy to people who may be browsing executable files. It at least acknowledges their industry but doesn't allow them to get in trouble, or worse, delete the file because it doesn't appear to do anything.
Note that modules (both normal and class) now have properties. The class module properties deserve some explanation. Table 16.3 explains the various properties for class modules.
Property |
Values |
Comments |
Instancing |
0—Not Creatable 1—Creatable Single Use 2—Creatable Multi-Use |
Not Creatable means you can only create instances of your server in your own project. Single Use means that you can create instances in and outside of your project but each instance requires a separate copy of the server to be run. Multi-Use allows multiple instances to share the same code segment. This the required setting for DLLs. |
Name |
Visual Basic's internal name for the module. |
This must follow Visual Basic variable naming conventions. It is also a property of normal modules. |
Public |
True False |
When True, your object is visible to and usable by other applications. It is the required setting for objects you publish for use by others. |
Finally, after you compile your application, you need to register it on your system as an OLE 2.x server. If you use the Setup Wizard to package your application for distribution, the SETUP.EXE you create registers your application on the target system.
You can register it by hand by using the REGSVR??.EXE program that ships with Visual Basic. The ?? stands for 16 or 32 depending on the target system. You run it from the command line with your server's fully qualified path and file as a parameter. The
following line is the command to register the example server on your system, presuming you place it with other common DLLs in your system directory:
C:REGSVR32.EXE C:\WINDOWS\SYSTEM\RBRUN.DLL
If you publish your server as an executable file, it registers itself the first time it is run or if you run it with the /REGSERVER switch.
MYAPP.EXE /REGSERVER
This does not launch the application but registers it with the system and exposes its type library. Figure 16.11 shows the type library for the rbRun.DLL exposed in VBA Companion.
Figure 16.11. The type library for rbRun.DLL in VBA Companion.
The capability of creating OLE 2.x servers is probably the most significant feature in Visual Basic 4.0. This gives Visual Basic programmers access to a whole realm of software production that is likely to become very important with the release of OLE
2.x—aware operating systems like Windows 95.
Visual Basic 4.0 takes this one step further by exposing its own type library and allowing other applications to "drive" it. This means that developers can create add-ins that customize and automate the behavior of Visual Basic's development
environment. Examples of this capability ship with Visual Basic. A simple example is the Align program which aligns controls on a form, but the Data Forms Designer example shows sample code for automated form development based on a data table. The Data
Manager application also functions as an add-in.
In order to transform your simple Run dialog into an add-in to Visual Basic, you need to open a new project in Visual Basic and set a reference in the Tools References dialog box to the rbRun Run Dialog object (see Figure 16.12).
Figure 16.12. The References dialog box from Visual Basic 4.0.
In addition, you need to add two class modules and a code module to the project. Note that this project has no form modules in it.
The first class module, RunAddIn, contains the code for connecting the add-in application to Visual Basic.
VERSION 1.0 CLASS BEGIN MultiUse = -1 'True END Attribute VB_Name = "RunAddIn" Attribute VB_Creatable = True Attribute VB_Exposed = True Option Explicit 'Storage for the instance of VBInstance given to us in ConnectAddIn Dim ThisInstance As Object 'Storage for the menu and menuline objects created when the add-in adds its own _menu 'and menulines to Visual Basic Dim RunMenuLine As Object 'Set up an instance of the menu line Clicked() Event Handlers Dim RunHandler As New DoDoRunRun 'Storage for the cookies that are passed back 'from ConnectEvents Dim RunConnectCookie As Long Sub ConnectAddIn(VBInstance As Object) Set ThisInstance = VBInstance Set RunMenuLine = ThisInstance.AddInMenu.MenuItems.Add("Run...") Set RunHandler.VBInstance = VBInstance RunConnectCookie = RunMenuLine.ConnectEvents(RunHandler) End Sub Sub DisconnectAddIn(Mode As Integer) RunMenuLine.DisconnectEvents RunConnectCookie ThisInstance.AddInMenu.MenuItems.Remove RunMenuLine Set ThisInstance = Nothing End Sub
Notice that there are module-level object values to hold references to the calling instance of Visual Basic and other variables that represent objects in the Visual Basic environment. The most significant example in this case is the MenuLine object,
which represents an entry on the Add-Ins menu in the development environment. The two required procedures that the Visual Basic Add-In Manager uses to install and remove the add-in are in this module. Note that to register an add-in you store a reference
to the instance of Visual Basic, create the menu lines you need, set a reference to the Visual Basic instance in the EventHandler modules (in this case, it is the other class module, DoDoRunRun (pardon the whimsy). Finally you use the ConnectEvent method
of the MenuLine object to retrieve a "cookie" (actually a long pointer to a function in C or C++). To disconnect, the process is neatly reversed, removing the event connect, deleting the menu entries, and releasing the reference to Visual Basic.
The second class module, DoDoRunRun, manages the operation of the Run dialog.
VERSION 1.0 CLASS BEGIN MultiUse = -1 'True END Attribute VB_Name = "DoDoRunRun" Attribute VB_Creatable = False Attribute VB_Exposed = True Option Explicit Public VBInstance As Object Private dlg As New RunClass Public Sub AfterClick() dlg.Run dlg.Execute End Sub
The AfterClick() method of this class is required for an add-in. It represents the action taken on the Click event on the menu item. The settings for the Instancing and Public properties of this module are interesting. When a module is Instancing=3,
(Creatable Multi-Use) and Public = True, the object is a Creatable OLE 2.x object. That means that it can be instanced with the New keyword in a Set or Dim statement or with the GetObject or CreateObject functions in Visual Basic. When Public = False, then
the object is a programmable object, that is, it can be controlled from outside of the module, but it can't be independently instantiated. Using VBA Companion, you see this distinction of creatable versus programmable objects in all of the object
hierarchies you browse. This is an important consideration in object design (a topic that needs to be dealt with elsewhere). Figure 16.13 shows the Run item on Visual Basics Tools menu, and Figure 16.14 shows the Run dialog launched.
Figure 16.13. The Run dialog option on the Add-Ins menu.
Figure 16.14. The Run dialog running in the Visual Basic development environment.
Programming other application's objects is covered well in any number of references and is not a feature new to this version of Visual Basic. Suffice it to say that Visual Basic continues to be the environment of choice for customization and
inter-application coordination when the applications are OLE aware.
Visual Basic 4.0 offers a range of new OLE features including support for compound document objects in forms and in the OLE container control, menu, toolbar, and status bar negotiation with OLE document objects. For programmers, the more valuable
changes are in the support for OLE automation, including the ability to develop OLE automation server application and dynamic link libraries. Visual Basic utilities can now be developed in Visual Basic itself and installed in the development environment.
Visual Basic now supports multiple instances so that Visual Basic can be used to debug OLE servers and add-in programs. An entire range of new business opportunities for Visual Basic programmers flows from these features.
Object Oriented Programming (OOP) requires the implementation of four qualities in a programming language: abstraction, encapsulation, polymorphism, and inheritance. Abstraction is a process of dividing your program into chunks that have a correlation
with the real world problems the program is meant to solve. Rather than focusing on the function as the unit of interest, in OOP you focus on the object. This means that you can deal with more of the program at once without straining your mental faculties,
so to speak.
Encapsulation is the process of making an application out of a series of black boxes which have predictable input and output, but whose inner functioning is unknown and unknowable.
Polymorphism is a more difficult concept to grasp. The bottom line is that different objects can interact without knowing before runtime what the other objects will be. A good example might be a computer game that supports different rockets. Each of
these rockets exposes a trajectory property that varies with the design of the rocket. A screen painting module could interact with these rockets and access their trajectory property to paint them differently on the screen. It need not know beforehand how
many of which kinds of rockets there are in order to successfully managing their presentation on screen.
The argument has raged for the life of Visual Basic about whether it qualifies as an object-oriented development tool. In the earlier versions of Visual Basic, the only claim to OOP was the use of controls and forms which had some object-oriented
features in that they had both properties (data) and methods (procedures that manipulate the data). Visual Basic added a further dimension to this through the event-driven model. Events represented the interaction between the user and the objects exposed
by the programmer, but for any reasonably rigorous definition of OOP, Visual Basic did not begin to qualify.
Inheritance is a process whereby one class of objects inherits all the qualities of a parent class of objects simply by reference, that is by the programmer stating in the object that it is of type X.
Many developers attempted to support OOP principles by separating data and procedures into separate code modules. Version 3.0 supported the use of Private variables and procedures. This allowed more abstraction and encapsulation; however, this was not a
feature of the development environment but an innovation by programmers.
With the addition of class modules, more features of OOP are accessible to Visual Basic programmers. Abstraction and encapsulation are easily implemented with these modules. Inheritance is not supported by reference, but with careful planning of
objects, one can accomplish a sort of inheritance by containment. For example, a class that managed File I/O and error checking could be included as a private member of a class that managed the file content. The second class inherits the functions of the
other class by containment. Granted, this is not accomplished as simply and transparently as it is in C++, but the opportunity is at least seminally present.
Similarly, with careful design, polymorphism is supported in Visual Basic. Object references can be changed transparently, so that the same variable could represent the rocket from Apollo 13 and later represent the rocket of the space shuttle with
different values in properties of the same name and with different functionality exposed in methods of the same name. In this way, the details of which object is interacting at which time need not be established until run-time.
The bottom line is that Visual Basic is evolving into an object-oriented language but does not fully embrace all the features of an OOP (at least as it is "religiously" understood). The object-oriented feature of Visual Basic, however, does
present new opportunities for better architectural designs and more stable software.
OLE and object oriented design are complex topics, and both are having significant influence on the computer industry at this time. Visual Basic offers an array of tools to participate in this revolution. To realize this promise, programmers need a
fairly detailed understanding of the processes involved. Visual Basic programmers have the opportunity to exploit these features without enduring the pain of C and C++ (pardon the prejudice). For further information, consider some of the following
references:
For more information on OLE 2.x:
For more information on OLE Automation with Microsoft Office:
For in-depth discussion of object-oriented design,
Finally, for overall information on software construction and design: